package com.sikaryofficial.qrcode.controller;

import cn.hutool.core.text.CharSequenceUtil;
import com.sikaryofficial.common.core.domain.R;
import com.sikaryofficial.common.core.exception.ServiceException;
import com.sikaryofficial.common.core.utils.HiResultUtil;
import com.sikaryofficial.common.core.utils.ip.IpUtils;
import com.sikaryofficial.common.core.web.controller.BaseController;
import com.sikaryofficial.common.core.web.domain.HiResult;
import com.sikaryofficial.common.security.utils.SecurityUtils;
import com.sikaryofficial.qrcode.config.ActivityConfig;
import com.sikaryofficial.qrcode.config.QrcodeRedirectConfig;
import com.sikaryofficial.qrcode.domain.dto.req.ScanTaskReq;
import com.sikaryofficial.qrcode.domain.dto.resp.ScanNumResp;
import com.sikaryofficial.qrcode.manager.QrSkeCallbackManager;
import com.sikaryofficial.qrcode.service.ProductQrMongoService;
import com.sikaryofficial.qrcode.service.brand.cache.BrandTasteCacheService;
import com.sikaryofficial.system.api.RemotePointBalanceService;
import com.sikaryofficial.system.api.model.ScanTaskVO;
import com.sikaryofficial.system.api.model.UserPointResultVO;
import com.sikaryofficial.system.api.model.product.BrandTasteDTO;
import com.sikaryofficial.system.api.model.qrcode.BrandTasteScanReq;
import com.sikaryofficial.system.api.model.skeremote.BrandTasteSecurityReq;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Objects;
import cn.hutool.core.util.URLUtil;
import java.net.URL;
import java.util.Optional;

/**
 * 品牌口味Controller
 *
 * @author qinjinyuan
 * @date 2023-11-07
 */
@RestController
@RequestMapping("/base")
@Api(tags = "二维码基础服务")
@Slf4j
public class QrBaseController extends BaseController {
    private static final String errorMsg = "the param is error";
    private static final String SCAN_REQ_CONSTANT = "1";
    @Autowired
    private ProductQrMongoService productQrService;
    @Autowired
    private BrandTasteCacheService brandCacheService;
    @Autowired
    private QrSkeCallbackManager qrSkeCallbackManager;
    @Autowired
    private ActivityConfig activityConfig;
    @Autowired
    private BrandTasteCacheService brandTasteCacheService;
    @Autowired
    private RemotePointBalanceService pointBalanceService;

    @Autowired
    private QrcodeRedirectConfig qrcodeRedirectConfig;
    @PostMapping("/scanTask")
    @ApiOperation("扫码任务积分获取")
    public R<UserPointResultVO> scanTask(@RequestBody ScanTaskReq scanTaskReq) {
        return R.ok(getScanTaskPoint(scanTaskReq));
    }

    private UserPointResultVO getScanTaskPoint(ScanTaskReq scanTaskReq) {
        String param = extractParamFromUrl(scanTaskReq.getSourceUrl(), "p");
        UserPointResultVO resultVO = UserPointResultVO.builder().getPointsFlag(false).pointsDetailValue(0).build();
        if (!verifySourceUrl(scanTaskReq.getSourceUrl())) {
            log.error("不包含产品二维码，无法获取积分");
            return resultVO;
        }
        if (CharSequenceUtil.isBlank(param)) {
            log.error("无法获取p参数，无法获取积分");
            return resultVO;
        }
        // 登录用户
        if (Objects.equals(SecurityUtils.getUserId(), 0L)) {
            log.error("非登录用户，不获取积分");
            return resultVO;
        }
        // 扫码任务得积分
        if (CharSequenceUtil.isBlank(param)) {
            log.error("参数为空");
            return resultVO;
        }
        BrandTasteDTO brandTasteDTO = brandTasteCacheService.getProductByParam(param);
        if (Objects.isNull(brandTasteDTO)) {
            log.error("获取产品信息失败");
        }
        try {
            R<UserPointResultVO> result = pointBalanceService.scanTask(ScanTaskVO.builder()
                    .userId(SecurityUtils.getUserId())
                    .brandTasteId(Optional.ofNullable(brandTasteDTO)
                            .map(BrandTasteDTO::getBrandTasteId)
                            .orElse(0L))
                    .param(param)
                    .build());
            return result.getData();
        } catch (Exception e) {
            log.error("扫码任务积分获取失败");
            return resultVO;
        }
    }

    private boolean verifySourceUrl(String sourceUrl) {
        return sourceUrl.contains(qrcodeRedirectConfig.getDomain());
    }

    private String extractParamFromUrl(String url, String paramName) {
        if (CharSequenceUtil.isBlank(url) || CharSequenceUtil.isBlank(paramName)) {
            return null;
        }

        try {
            URL parsedUrl = URLUtil.url(url);
            String query = parsedUrl.getQuery();
            if (CharSequenceUtil.isBlank(query)) {
                return null;
            }

            String[] params = query.split("&");
            for (String param : params) {
                String[] keyValue = param.split("=");
                if (keyValue.length >= 2 && paramName.equals(keyValue[0])) {
                    return keyValue[1];
                }
            }
        } catch (Exception e) {
            log.error("解析URL参数失败: url={}, paramName={}", url, paramName, e);
        }

        return null;
    }

    /**
     * 判定用户是否扫码获取产品100积分
     */
    @GetMapping("/scanCodeExtPoints/{param}")
    @ApiOperation("判定用户是否扫码获取产品100积分")
    public HiResult<Boolean> scanCodeExtPoints(@PathVariable("param") String param) {
        if (CharSequenceUtil.isBlank(param)) {
            return HiResultUtil.success(false);
        }
        if (brandCacheService.scanCodeExtPoints(param)) {
            return HiResultUtil.success(false);
        }
        return HiResultUtil.success(productQrService.verifyScanCode(param));
    }

    /**
     * 二维码防伪
     */
    @PostMapping("/qrSecurity")
    @ApiOperation("二维码防伪-提供SKE外部服务")
    public R<Boolean> qrSecurity(@Validated @RequestBody BrandTasteSecurityReq param
            , @RequestHeader(value = "User-Agent", required = false) String userAgent) {
        brandCacheService.productCodeExist(param.getP());
        // 存在则进行扫描数量上报
        Boolean result = brandCacheService.reportScansNum(param.getP());
        // 记录详情数据
        qrSkeCallbackManager.callbackForUserDetail(IpUtils.getIpAddr(), param.getP(), SecurityUtils.getUserId(), userAgent);
        // 调用SKE回调
        qrSkeCallbackManager.callback(param);
        return R.ok(result);
    }

    /**
     * 上报扫码次数
     */
    @PostMapping("/reportScanNum")
    @ApiOperation("上报扫码次数")
    public R<Boolean> reportScansNum(@Validated @RequestBody BrandTasteScanReq param
            , @RequestHeader(value = "User-Agent", required = false) String userAgent) {
        if (!CharSequenceUtil.equals(SCAN_REQ_CONSTANT, param.getE())) {
            throw new ServiceException(errorMsg);
        }
        brandCacheService.productCodeExist(param.getP());
        // 存在则进行扫描数量上报
        Boolean result = brandCacheService.reportScansNum(param.getP());
        // 记录详情数据
        qrSkeCallbackManager.callbackForUserDetail(IpUtils.getIpAddr(), param.getP(), SecurityUtils.getUserId(), userAgent);
        // 调用SKE回调
        qrSkeCallbackManager.callback(BrandTasteSecurityReq.builder()
                .p(param.getP())
                .ipAddress(IpUtils.getIpAddr())
                .build());
        return R.ok(result);
    }

    /**
     * 统计扫码次数
     * <p>
     * 历史版本-非主站使用
     */
    @PostMapping("/countScanNum")
    @ApiOperation("统计扫码次数")
    public R<Integer> countScanNum(@Validated @RequestBody BrandTasteScanReq param) {
        if (!CharSequenceUtil.equals(SCAN_REQ_CONSTANT, param.getE())) {
            throw new ServiceException(errorMsg);
        }
        brandCacheService.productCodeExist(param.getP());
        // 存在则进行扫描数量上报
        return R.ok(brandCacheService.countScanNum(param.getP()).getScanCodeNum());
    }

    /**
     * 统计扫码次数
     * <p>
     * 主站专用
     */
    @PostMapping("/countScanNumMain")
    @ApiOperation("统计扫码次数Main")
    public R<ScanNumResp> countScanNumMain(@Validated @RequestBody BrandTasteScanReq param) {
        if (!CharSequenceUtil.equals(SCAN_REQ_CONSTANT, param.getE())) {
            throw new ServiceException(errorMsg);
        }
        BrandTasteDTO brandTasteDTO = brandCacheService.productCodeExist(param.getP());
        // 存在则进行扫描数量上报
        ScanNumResp result = new ScanNumResp();
        result.setScanNum(brandCacheService.countScanNum(param.getP()).getScanCodeNum());
        result.setBrandNo(Objects.isNull(brandTasteDTO) ? "" : brandTasteDTO.getBrandNo());
        result.setBrandTasteId(Objects.isNull(brandTasteDTO) ? 0L : brandTasteDTO.getBrandTasteId());
        // 增加特殊定制逻辑-指定具体的产品，才显示活动ID
        if (Boolean.TRUE.equals(activityConfig.isHasDisplayActivityId())
                && Objects.nonNull(brandTasteDTO)
                && activityConfig.getSpecialProductIds().contains(brandTasteDTO.getBrandTasteId())) {
            result.setActivityId(activityConfig.getSpecialActivityId());
            result.setActivityType(activityConfig.getActivityType());
        }
        return R.ok(result);
    }

    @GetMapping("/existProductQrCode/{param}")
    @ApiOperation("二维码存在性判定")
    public R<Boolean> existProductQrCode(@PathVariable(name = "param") String param) {
        return R.ok(productQrService.existProductQrCode(param));
    }

    @GetMapping("/verifyScanCode/{param}")
    @ApiOperation("判定是否被扫码(是否获取100积分):true-被扫码;false-未扫码")
    public R<Boolean> verifyScanCode(@PathVariable(name = "param") String param) {
        return R.ok(productQrService.verifyScanCode(param));
    }

    @GetMapping("/updateProductQrData/{param}")
    @ApiOperation("设置扫码状态(是否获取100积分)")
    public R<Boolean> updateProductQrData(@PathVariable(name = "param") String param) {
        return R.ok(productQrService.updateProductQrData(param));
    }

    /**
     * 重定向接口
     * @param param
     * @return
     */

    @GetMapping("/redirectUrl/{param}")
    @ApiOperation("设置扫码状态(是否获取100积分)")
    public R<Boolean> redirectUrl(@PathVariable(name = "param") String param) {
        return R.ok(productQrService.updateProductQrData(param));
    }
}
